﻿using Inovout.Cloud.Data.Blob.Models;
using Inovout.Cloud.Data.Blob.Service;
using Inovout.Cloud.Storage.Models;
using Inovout.Cloud.Storage.Repositories;
using Inovout.Services;
using NHibernate.Criterion;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace Inovout.Cloud.Storage.Services
{
    public class ObjectService : RepositoryService<Object>, IObjectService
    {
        IFileService fileService;
        IBucketService bucketService;
        public ObjectService(IFileService fileService, IBucketService bucketService)
        {
            this.fileService = fileService;
            this.bucketService = bucketService;
        }
        private File GetObjectFile(Bucket bucket, Object storageObject)
        {
            string objectFilePath = bucket.Folder.Path + storageObject.Name;
            File objectFile = fileService.FindByPath(objectFilePath);
            if (objectFile==null)
            {
                objectFile = fileService.Create(bucket.Folder, storageObject.Name, storageObject.Length);
            }
            return objectFile;
        }
        public override void Save(Object entity)
        {
            //todo: 需调用WebHdfs查询文件是否存在？
            entity.File = GetObjectFile(entity.Bucket, entity);
            base.Save(entity);
        }
        public Object Find(Bucket bucket, string objectName)
        {
            return base.Repository.Find(Restrictions.Eq("Bucket.Id", bucket.Id), Restrictions.Eq("Name", objectName).IgnoreCase());
        }
        public IEnumerable<Object> FindAllByBucket(int bucketId)
        {
            return base.Repository.FindAll(Restrictions.Eq("Bucket.Id", bucketId));
        }
        public void Delete(Bucket bucket, string objectName)
        {
            Object bucketObject = Find(bucket, objectName);

            Repository.Delete((object)bucketObject.Id);
            fileService.Delete(bucketObject.File);
        }
        public Task<System.IO.Stream> GetStreamAsync(Object storageObject, int offset, int length)
        {
            return fileService.GetStreamAsync(storageObject.File, offset, length);
        }



        public System.IO.Stream GetLocalStream(Bucket bucket, string objectName)
        {
            Object storageObject = base.Repository.Find(Restrictions.Eq("Path", GetLocalObjectPath(bucket, objectName)));
            return fileService.GetLocalStream(storageObject.File);
           
        }

        private string GetLocalObjectPath(Bucket bucket, string objectName)
        {
            if (bucket.Path.EndsWith("\\"))
            {
                return bucket.Path + objectName;
            }
            else
            {
                return bucket.Path + "\\" + objectName;
            }
        }

        private string GetObjectPath(Bucket bucket, string objectName)
        {
            if (bucket.Path.EndsWith("/"))
            {
                return bucket.Path + objectName;
            }
            else
            {
                return bucket.Path + "/" + objectName;
            }
        }
        public Task<System.IO.Stream> GetStreamAsync(Bucket bucket, string objectName, int offset, int length)
        {
            Object storageObject = base.Repository.Find(Restrictions.Eq("Path", GetObjectPath(bucket, objectName)));
            return GetStreamAsync(storageObject, offset, length);
        }

        public Task<System.IO.Stream> GetStreamAsync(Bucket bucket, string objectName)
        {
            Object storageObject = base.Repository.Find(Restrictions.Eq("Path", GetObjectPath(bucket, objectName)));
            return GetStreamAsync(storageObject, 0, (int)storageObject.Length);
        }
        public async Task<Object> CopyAsAsync(string sourceBucketName, string sourceObjectName, string destinationBucketName, Object destinationObject)
        {
            Bucket sourceBucket = bucketService.FindByName(sourceBucketName);
            Object sourceObject = this.Find(sourceBucket, sourceObjectName);
            Bucket destinationBucket = bucketService.FindByName(destinationBucketName);

            destinationObject.Length = sourceObject.Length;
            destinationObject.Bucket = destinationBucket;
            this.Save(destinationObject);
            return await fileService.CopyAsAsync(sourceObject.File, destinationObject.File).ContinueWith<Object>(
             t =>
             {
                 if (t.Result)
                 {
                     return destinationObject;
                 }
                 throw new System.Exception("Copy " + sourceObject.File.Path + " To " + destinationObject.File.Path);
             }
                );
        }

        protected ObjectRepository ObjectRepository
        {
            get { return (ObjectRepository)base.Repository; }
        }
        public Object FindByFile(File file)
        {
            return ObjectRepository.FindByFile(file);
        }
    }
}
